/**
 * WebSocket 管理器
 * 支持自动重连、心跳检测、消息队列、事件监听
 * 
 * 消息类型：
 * - heart_beat: 心跳消息
 * - chat: 聊天消息
 */

import webSocket from '@ohos.net.webSocket' // eslint-disable-line

// WebSocket 服务器地址
const WS_URL = 'ws://192.168.17.1:18080/chat/ws'

// WebSocket 消息结构（泛型）
export interface WSMessage<T = any> {
  msgType: string  // 消息类型: heart_beat | chat
  data: T          // 消息数据（泛型）
}

// ============ 聊天消息内容类型定义 ============

// 1. 文本消息
export interface TextMessageContent {
  type: 'TEXT'
  text: string
}

// 2. 图片消息
export interface ImageMessageContent {
  type: 'IMAGE'
  imageUrl: string
  width: number
  height: number
}

// 3. 语音消息
export interface VoiceMessageContent {
  type: 'VOICE'
  audioUrl: string
  duration: number  // 秒
  read: boolean
}

// 4. 职位卡片消息
export interface JobCardMessageContent {
  type: 'JOB_CARD'
  jobId: string
  jobName: string
  tags?: string
  expYears?: string
  edu?: string
  beginSalary?: number
  endSalary?: number
  monthlySalary?: number
  city?: string
  userId: string
  name: string
  position?: string
  face?: string
  companyId: string
  companyName: string
  peopleSize?: string
  financStage?: string
}

// 5. 简历文件消息
export interface ResumeFileMessageContent {
  type: 'RESUME_FILE'
  id: number
  userId: string
  fileName: string
  fileSizeMb: number
  fileType: string
  fileUrl: string
}

// 6. 在线简历消息
export interface ResumeOnlineMessageContent {
  type: 'RESUME_ONLINE'
  resumeExpId: string
}

// 7. 面试邀请消息
export interface InterviewInviteMessageContent {
  type: 'INTERVIEW_INVITE'
  interviewId: string
}

// 8. 面试回复消息
export interface InterviewReplyMessageContent {
  type: 'INTERVIEW_REPLY'
  originalMsgId: string  // 原邀请消息ID
  accepted: boolean      // true:接受, false:拒绝
}

// 聊天消息内容联合类型
export type ChatMessageContent =
  | TextMessageContent
  | ImageMessageContent
  | VoiceMessageContent
  | JobCardMessageContent
  | ResumeFileMessageContent
  | ResumeOnlineMessageContent
  | InterviewInviteMessageContent
  | InterviewReplyMessageContent

// 消息类型枚举（对应后端 ChatMessageType）
export enum ChatMessageType {
  TEXT = 10,              // 文本消息
  IMAGE = 11,             // 图片消息
  VOICE = 12,             // 语音消息
  VIDEO = 13,             // 视频消息
  INTERVIEW_INVITE = 14,  // 面试邀请
  INTERVIEW_REPLY = 15,   // 面试回复
  JOB_CARD = 16,          // 职位卡片
  RESUME_FILE = 17,       // 简历文件
  RESUME_ONLINE = 18      // 在线简历
}

// 聊天消息数据结构（发送给服务器的实际消息）
export interface ChatMessageData {
  sessionId: string          // 会话ID
  senderId: string           // 发送者ID
  receiveId: string          // 接收者ID
  msgType: number            // 消息类型（对应 ChatMessageType 的 code）
  content: ChatMessageContent // 消息内容
  createTime: number         // 消息发送时间（毫秒级时间戳）
}

// 事件监听器类型
type EventListener<T = any> = (data: T) => void

// WebSocket 配置
export interface WSConfig {
  url: string
  token?: string                  // 认证 token（放在请求头）
  heartbeatInterval?: number      // 心跳间隔（毫秒），默认 30000
  reconnectInterval?: number      // 重连间隔（毫秒），默认 3000
  maxReconnectAttempts?: number   // 最大重连次数，默认 5，-1 表示无限重连
  autoConnect?: boolean           // 是否自动连接，默认 true
}

class WebSocketClient {
  private ws: webSocket.WebSocket | null = null
  private config: WSConfig | null = null
  private isConnected: boolean = false
  private isConnecting: boolean = false
  private reconnectAttempts: number = 0
  private heartbeatTimer: number = -1
  private reconnectTimer: number = -1
  private messageQueue: WSMessage[] = []  // 消息队列
  private eventListeners: Map<string, EventListener[]> = new Map()

  /**
   * 连接 WebSocket
   */
  async connect(config: WSConfig): Promise<void> {
    if (this.isConnected || this.isConnecting) {
      console.log('[WebSocket] 已经连接或正在连接中')
      return
    }

    this.config = {
      heartbeatInterval: 30000,
      reconnectInterval: 3000,
      maxReconnectAttempts: 5,
      autoConnect: true,
      ...config
    }

    await this.createConnection()
  }

  /**
   * 创建连接
   */
  private async createConnection(): Promise<void> {
    if (!this.config) {
      console.error('[WebSocket] 配置信息为空')
      return
    }

    try {
      this.isConnecting = true
      console.log('[WebSocket] 开始连接:', this.config.url)

      this.ws = webSocket.createWebSocket()
      this.setupEventListeners()

      // 如果配置中有 token，则添加到请求头
      if (this.config.token) {
        await this.ws.connect(this.config.url, {
          header: {
            'authorization': this.config.token
          }
        })
      } else {
        await this.ws.connect(this.config.url)
      }

    } catch (error) {
      console.error('[WebSocket] 连接失败:', error)
      this.isConnecting = false
      this.handleReconnect()
    }
  }

  /**
   * 设置事件监听
   */
  private setupEventListeners(): void {
    if (!this.ws) return

    // 连接打开
    this.ws.on('open', (err, value) => {
      if (err) {
        console.error('[WebSocket] 连接打开失败:', JSON.stringify(err))
        return
      }

      console.log('[WebSocket] 连接成功, value:', JSON.stringify(value))
      this.isConnected = true
      this.isConnecting = false
      this.reconnectAttempts = 0

      this.emit('open', null)
      this.startHeartbeat()
      this.flushMessageQueue()
    })

    // 接收消息
    this.ws.on('message', (err, value) => {
      if (err) {
        console.error('[WebSocket] 接收消息失败:', err)
        return
      }

      try {
        const message: WSMessage = typeof value === 'string'
          ? JSON.parse(value)
          : value

        console.log('[WebSocket] 收到消息:', JSON.stringify(message))

        // 处理聊天消息（特殊处理，需要解析 JSON）
        if (message.msgType === 'chat') {
          // data 可能是字符串，需要解析
          const chatData = typeof message.data === 'string' 
            ? JSON.parse(message.data) 
            : message.data
          
          console.log('[WebSocket] 解析后的聊天消息:', JSON.stringify(chatData))
          
          // 触发聊天消息事件，传递解析后的数据
          this.emit('chat', chatData)
          
          // 触发通用 message 事件
          this.emit('message', message)
        } else {
          // 其他消息类型，直接触发事件
          if (message.msgType) {
            this.emit(message.msgType, message.data)
          }
          
          // 触发通用 message 事件
          this.emit('message', message)
        }

      } catch (error) {
        console.error('[WebSocket] 消息解析失败:', error)
      }
    })

    // 连接关闭
    this.ws.on('close', (err, value) => {
      console.log('[WebSocket] 连接关闭, code:', JSON.stringify(value))
      this.isConnected = false
      this.isConnecting = false

      this.stopHeartbeat()
      this.emit('close', value)

      if (this.config?.autoConnect) {
        this.handleReconnect()
      }
    })

    // 连接错误
    this.ws.on('error', (err) => {
      // 判断是否是真正的错误（code 200 表示成功，不是错误）
      if (err && typeof err === 'object' && 'code' in err && err.code === 200) {
        console.log('[WebSocket] 收到成功响应:', JSON.stringify(err))
        return
      }
      
      console.error('[WebSocket] 连接错误:', JSON.stringify(err))
      this.emit('error', err)
    })
  }

  /**
   * 发送消息
   */
  send<T = any>(msgType: string, data: T): void {
    const message: WSMessage<T> = { msgType, data }

    if (!this.isConnected || !this.ws) {
      console.log('[WebSocket] 未连接，消息加入队列:', message)
      this.messageQueue.push(message)
      return
    }

    try {
      const msgStr = JSON.stringify(message)
      this.ws.send(msgStr, (err) => {
        if (err) {
          console.error('[WebSocket] 发送消息失败:', err)
          this.messageQueue.push(message)
        } else {
          console.log('[WebSocket] 消息发送成功:', JSON.stringify(message))
        }
      })
    } catch (error) {
      console.error('[WebSocket] 消息序列化失败:', error)
    }
  }

  /**
   * 发送原始消息对象（如果需要完全自定义消息结构）
   */
  sendRaw(message: WSMessage): void {
    if (!this.isConnected || !this.ws) {
      console.log('[WebSocket] 未连接，消息加入队列:', message)
      this.messageQueue.push(message)
      return
    }

    try {
      const msgStr = JSON.stringify(message)
      this.ws.send(msgStr, (err) => {
        if (err) {
          console.error('[WebSocket] 发送消息失败:', err)
          this.messageQueue.push(message)
        } else {
          console.log('[WebSocket] 消息发送成功:', message)
        }
      })
    } catch (error) {
      console.error('[WebSocket] 消息序列化失败:', error)
    }
  }

  /**
   * 发送心跳
   */
  private sendHeartbeat(): void {
    this.send('heart_beat', { timestamp: Date.now() })
  }

  /**
   * 开始心跳检测
   */
  private startHeartbeat(): void {
    if (!this.config?.heartbeatInterval) return

    this.stopHeartbeat()

    this.heartbeatTimer = setInterval(() => {
      if (this.isConnected) {
        this.sendHeartbeat()
      }
    }, this.config.heartbeatInterval)

    console.log('[WebSocket] 心跳启动，间隔:', this.config.heartbeatInterval)
  }

  /**
   * 停止心跳检测
   */
  private stopHeartbeat(): void {
    if (this.heartbeatTimer !== -1) {
      clearInterval(this.heartbeatTimer)
      this.heartbeatTimer = -1
      console.log('[WebSocket] 心跳停止')
    }
  }

  /**
   * 处理重连
   */
  private handleReconnect(): void {
    if (!this.config) return

    const { maxReconnectAttempts = 5, reconnectInterval = 3000 } = this.config

    if (maxReconnectAttempts !== -1 && this.reconnectAttempts >= maxReconnectAttempts) {
      console.error('[WebSocket] 达到最大重连次数，停止重连')
      this.emit('maxReconnect', this.reconnectAttempts)
      return
    }

    this.reconnectAttempts++
    console.log(`[WebSocket] 准备重连 (${this.reconnectAttempts}/${maxReconnectAttempts === -1 ? '∞' : maxReconnectAttempts})`)

    if (this.reconnectTimer !== -1) {
      clearTimeout(this.reconnectTimer)
    }

    this.reconnectTimer = setTimeout(() => {
      console.log('[WebSocket] 开始重连...')
      this.createConnection()
    }, reconnectInterval)
  }
  /**
   * 发送消息队列中的消息
   */
  private flushMessageQueue(): void {
    if (this.messageQueue.length === 0) return

    console.log('[WebSocket] 发送队列中的消息，数量:', this.messageQueue.length)

    while (this.messageQueue.length > 0) {
      const message = this.messageQueue.shift()
      if (message) {
        this.sendRaw(message)
      }
    }
  }

  /**
   * 添加事件监听器
   * @param event 事件名称（可以是消息类型 msgType，或系统事件：open, close, error, message）
   * @param listener 监听器函数
   */
  on<T = any>(event: string, listener: EventListener<T>): void {
    if (!this.eventListeners.has(event)) {
      this.eventListeners.set(event, [])
    }
    this.eventListeners.get(event)?.push(listener)
  }

  /**
   * 移除事件监听器
   */
  off<T = any>(event: string, listener: EventListener<T>): void {
    const listeners = this.eventListeners.get(event)
    if (!listeners) return

    const index = listeners.indexOf(listener)
    if (index > -1) {
      listeners.splice(index, 1)
    }
  }

  /**
   * 移除某个事件的所有监听器
   */
  offAll(event: string): void {
    this.eventListeners.delete(event)
  }

  /**
   * 触发事件
   */
  private emit<T = any>(event: string, data: T): void {
    const listeners = this.eventListeners.get(event)
    if (!listeners || listeners.length === 0) return

    listeners.forEach(listener => {
      try {
        listener(data)
      } catch (error) {
        console.error(`[WebSocket] 事件监听器执行失败 (${event}):`, error)
      }
    })
  }

  /**
   * 断开连接
   */
  async disconnect(): Promise<void> {
    console.log('[WebSocket] 主动断开连接')

    // 禁用自动重连
    if (this.config) {
      this.config.autoConnect = false
    }

    this.stopHeartbeat()

    if (this.reconnectTimer !== -1) {
      clearTimeout(this.reconnectTimer)
      this.reconnectTimer = -1
    }

    if (this.ws) {
      try {
        await this.ws.close()
      } catch (error) {
        console.error('[WebSocket] 关闭连接失败:', error)
      }
      this.ws = null
    }

    this.isConnected = false
    this.isConnecting = false
    this.config = null
  }

  /**
   * 获取连接状态
   */
  getConnected(): boolean {
    return this.isConnected
  }

  /**
   * 清空消息队列
   */
  clearMessageQueue(): void {
    this.messageQueue = []
    console.log('[WebSocket] 消息队列已清空')
  }

  /**
   * 获取消息队列长度
   */
  getMessageQueueLength(): number {
    return this.messageQueue.length
  }

  /**
   * 便捷方法：使用 token 初始化连接
   * @param token 用户 token
   */
  async init(token: string): Promise<void> {
    await this.connect({
      url: WS_URL,
      token: token,                 // token 放在请求头
      heartbeatInterval: 30000,     // 30秒心跳
      reconnectInterval: 3000,      // 3秒重连
      maxReconnectAttempts: -1,     // 无限重连
      autoConnect: true
    })
  }

  /**
   * 发送聊天消息（通用方法）
   * 自动包装成 WsMsgDTO 格式发送
   */
  sendChatMessage(data: ChatMessageData): void {
    this.send('chat', data)
  }

  /**
   * 发送文本消息
   */
  sendTextMessage(
    sessionId: string,
    senderId: string,
    receiveId: string,
    text: string
  ): void {
    const content: TextMessageContent = {
      type: 'TEXT',
      text
    }
    const messageData: ChatMessageData = {
      sessionId,
      senderId,
      receiveId,
      msgType: ChatMessageType.TEXT,
      content,
      createTime: Date.now()
    }
    this.sendChatMessage(messageData)
  }

  /**
   * 发送图片消息
   */
  sendImageMessage(
    sessionId: string,
    senderId: string,
    receiveId: string,
    imageUrl: string,
    width: number,
    height: number
  ): void {
    const content: ImageMessageContent = {
      type: 'IMAGE',
      imageUrl,
      width,
      height
    }
    const messageData: ChatMessageData = {
      sessionId,
      senderId,
      receiveId,
      msgType: ChatMessageType.IMAGE,
      content,
      createTime: Date.now()
    }
    this.sendChatMessage(messageData)
  }

  /**
   * 发送语音消息
   */
  sendVoiceMessage(
    sessionId: string,
    senderId: string,
    receiveId: string,
    audioUrl: string,
    duration: number
  ): void {
    const content: VoiceMessageContent = {
      type: 'VOICE',
      audioUrl,
      duration,
      read: false
    }
    const messageData: ChatMessageData = {
      sessionId,
      senderId,
      receiveId,
      msgType: ChatMessageType.VOICE,
      content,
      createTime: Date.now()
    }
    this.sendChatMessage(messageData)
  }

  /**
   * 发送职位卡片消息
   */
  sendJobCardMessage(
    sessionId: string,
    senderId: string,
    receiveId: string,
    jobCard: Omit<JobCardMessageContent, 'type'>
  ): void {
    const content: JobCardMessageContent = {
      type: 'JOB_CARD',
      ...jobCard
    }
    const messageData: ChatMessageData = {
      sessionId,
      senderId,
      receiveId,
      msgType: ChatMessageType.JOB_CARD,
      content,
      createTime: Date.now()
    }
    this.sendChatMessage(messageData)
  }

  /**
   * 发送简历文件消息
   */
  sendResumeFileMessage(
    sessionId: string,
    senderId: string,
    receiveId: string,
    resumeFile: Omit<ResumeFileMessageContent, 'type'>
  ): void {
    const content: ResumeFileMessageContent = {
      type: 'RESUME_FILE',
      ...resumeFile
    }
    const messageData: ChatMessageData = {
      sessionId,
      senderId,
      receiveId,
      msgType: ChatMessageType.RESUME_FILE,
      content,
      createTime: Date.now()
    }
    this.sendChatMessage(messageData)
  }

  /**
   * 发送在线简历消息
   */
  sendResumeOnlineMessage(
    sessionId: string,
    senderId: string,
    receiveId: string,
    resumeExpId: string
  ): void {
    const content: ResumeOnlineMessageContent = {
      type: 'RESUME_ONLINE',
      resumeExpId
    }
    const messageData: ChatMessageData = {
      sessionId,
      senderId,
      receiveId,
      msgType: ChatMessageType.RESUME_ONLINE,
      content,
      createTime: Date.now()
    }
    this.sendChatMessage(messageData)
  }

  /**
   * 发送面试邀请消息
   */
  sendInterviewInviteMessage(
    sessionId: string,
    senderId: string,
    receiveId: string,
    interviewId: string
  ): void {
    const content: InterviewInviteMessageContent = {
      type: 'INTERVIEW_INVITE',
      interviewId
    }
    const messageData: ChatMessageData = {
      sessionId,
      senderId,
      receiveId,
      msgType: ChatMessageType.INTERVIEW_INVITE,
      content,
      createTime: Date.now()
    }
    this.sendChatMessage(messageData)
  }

  /**
   * 发送面试回复消息
   */
  sendInterviewReplyMessage(
    sessionId: string,
    senderId: string,
    receiveId: string,
    originalMsgId: string,
    accepted: boolean
  ): void {
    const content: InterviewReplyMessageContent = {
      type: 'INTERVIEW_REPLY',
      originalMsgId,
      accepted
    }
    const messageData: ChatMessageData = {
      sessionId,
      senderId,
      receiveId,
      msgType: ChatMessageType.INTERVIEW_REPLY,
      content,
      createTime: Date.now()
    }
    this.sendChatMessage(messageData)
  }
}

// 导出单例
export const ws = new WebSocketClient()

